#
#   GameObject.py
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; version 2 of the License.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   Copyright
#   Author: Nicholas F. Hoover
#   Contributors: Salvatore S. Gionfriddo
#   Created: 2007.06.18
#   Last Modified: 2007.07.24
#

import pygame
from Animation import Animation

RESOURCE_MANAGER = None

def gameObjectPosCompare(gameObject1, gameObject2):
    return gameObject1.rect.top - gameObject2.rect.top

class GameObject(pygame.sprite.Sprite):

    RIGHT = 0
    LEFT = 1
    
    DEFAULT_ANIMATI0N = 0
    DEFAULT_POSITION = (0,0)
    RECT_SIZE = (0,0)

    COLLISION_RECT_SIZE = (0,0)
    COLLISION_RECT_POSITION = (0,0)
    
    def __init__(self, fps = 30):
        pygame.sprite.Sprite.__init__(self)
        self.linkAnimations(fps)
        self.image = pygame.Surface(GameObject.RECT_SIZE) 
        self.rect = pygame.Rect(self.DEFAULT_POSITION, self.RECT_SIZE)
        (x,y) = self.DEFAULT_POSITION
        x += self.COLLISION_RECT_POSITION[0]
        y += self.COLLISION_RECT_POSITION[1]
        self.collision_rect = pygame.Rect((x,y), self.COLLISION_RECT_SIZE)
        self.attachedGameObjects = OrderedUpdatesDraw()
        self.reset()

    def reset(self):
        self.currentAnimation = self.DEFAULT_ANIMATION
        self.facing = self.RIGHT
        self.setPosition(self.DEFAULT_POSITION)
        self.updateCurrentImage()
        
    def setPosition(self,position):
        self.rect.topleft = position
        (x,y) = position
        x += self.COLLISION_RECT_POSITION[0]
        y += self.COLLISION_RECT_POSITION[1]
        self.collision_rect.topleft = (x,y)

    #generically loads all animation listed in animation table of subclasses
    def linkAnimations(self, fps):
        self.animations = range(self.NUM_ANIMATIONS *2)
        for element in self.ANIMATION_TABLE:
            if len(element) == 4:
                (index, name, frameTicks, keyFrame) = element
                rotate = False
            elif len(element) == 5:
                (index, name, frameTicks, keyFrame, rotate) = element
            print element
            self.animations[index] = Animation(RESOURCE_MANAGER.getAnimationFrames(name + '_Right'), frameTicks, keyFrame, rotate)
            self.animations[index + self.LEFT] = Animation(RESOURCE_MANAGER.getAnimationFrames(name + '_Left'), frameTicks, keyFrame, rotate)

    def updateCurrentAnimation(self):
        return self.animations[self.currentAnimation].update()

    def resetCurrentAnimation(self):
       self.animations[self.currentAnimation].reset()
       
    def updateCurrentImage(self):
        self.image = self.animations[self.currentAnimation].image
 
    def isActionComplete(self, action):
        return self.isActing(action) and self.animations[self.currentAnimation].isComplete()

    def isActionActive(self,action):
        return self.isActing(action) and self.animations[self.currentAnimation].isKeyFrame()
    
    def isActing(self,action):
        return self.getAnimationType() == action

    def setFacing(self, facing):
        self.facing = facing

    def getAnimationType(self):
        return self.currentAnimation - self.facing

    def setAnimation(self, animation, facing = None, reset = True):
        if facing != None: self.setFacing(facing)
        self.currentAnimation = animation + self.facing
        if reset:
           self.resetCurrentAnimation()
        
    def update(self):
        self.animations[self.currentAnimation].update()
        self.updateCurrentImage()

    def playSound(self, sound):
        RESOURCE_MANAGER.playSound(sound)
        
    def updateAttached(self):
       for sprite in self.attachedGameObjects:
          sprite.update()
    
    def attachGameObject(self, gameObject):
       self.attachedGameObjects.add(gameObject)

    def removeAttachedByType(self, removeType):
       for sprite in self.attachedGameObjects.sprites():
          if type(sprite) is removeType:
             self.attachedGameObjects.remove(sprite)
             
    def draw(self, surface):
       rects = self.attachedGameObjects.draw(surface)
       rects.append(surface.blit(self.image, self.rect))
       return rects


class TimedGameObject(GameObject):

   TICKS_TO_LIVE = 0

   def __init__(self, onKillFunction = None):
      GameObject.__init__(self)
      self.ticksLeft = self.TICKS_TO_LIVE
      self.onKill = onKillFunction
      
         
   def update(self):
      self.ticksLeft -= 1
      if self.ticksLeft == 0:
         if callable(self.onKill):
            self.onKill()
         self.kill()
      else:
         GameObject.update(self)
       
class OrderedUpdatesDraw(pygame.sprite.OrderedUpdates):
   def draw(self, surface):
      spritedict = self.spritedict
      surface_blit = surface.blit
      dirty = self.lostsprites
      self.lostsprites = []
      dirty_append = dirty.append
      for s in self.sprites():
         r = spritedict[s]
         newrects = s.draw(surface)
         newrect = newrects.pop()
         for rect in newrects:
            dirty_append(rect)
         if r is 0:
            dirty_append(newrect)
         else:
            if newrect.colliderect(r):
               dirty_append(newrect.union(r))
            else:
               dirty_append(newrect)
               dirty_append(r)
         spritedict[s] = newrect
      return dirty
